package cn.mldn.aio.server;

import cn.mldn.info.HostInfo;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.concurrent.CountDownLatch;

class EchoHandler implements CompletionHandler<Integer,ByteBuffer> {
    //<Integer,ByteBuffer>  读取个数     缓存的读取操作
    private AsynchronousSocketChannel clientChannel ;

    private boolean exit = false ;    // 是否结束交互过程，exit = true表示结束，exit = false表示继续

    public EchoHandler(AsynchronousSocketChannel clientChannel) {
        this.clientChannel = clientChannel ;
    }
    @Override
    public void completed(Integer result, ByteBuffer buffer) {
        buffer.flip() ; // 读取之前需要执行重置处理
        String readMessage = new String(buffer.array(),0,buffer.remaining()).trim() ;
        String writeMessage = "【ECHO】" + readMessage ;  // 回应的数据信息
        if ("byebye".equalsIgnoreCase(readMessage)) {
            writeMessage = "【EXIT】拜拜，下次再见！" ;
            this.exit = true ; // 结束后期的交互
        }
        this.echoWrite(writeMessage);
    }

    //服务端接受数据还需要往服务端写


    //echo是执行N多次的操作 里面还需要进行回调

    private void echoWrite(String content) {
        System.out.println("========================="+content);
        ByteBuffer buffer = ByteBuffer.allocate(100) ;
        buffer.put(content.getBytes()) ;// 向缓存中保存数据
        buffer.flip() ;
        this.clientChannel.write(buffer, buffer, new CompletionHandler<Integer, ByteBuffer>() {
            @Override
            public void completed(Integer result, ByteBuffer buf) {

                System.out.println(buf.hasRemaining());


                if (buf.hasRemaining()) {   // 缓存中是否有数据
                    //有数据，继续进行数据的输出
                    EchoHandler.this.clientChannel.write(buffer,buffer,this);
                } else {
                    if(EchoHandler.this.exit == false) {    // 还没有结束
                        // 是否结束交互过程，exit = true表示结束，exit = false表示继续

                        //是否结束  如果没有结束，继续读
                        //第一次的数据回应完成以后，第二次的数据继续过来 可能还有第二次的数据需要回应
                        ByteBuffer readBuffer = ByteBuffer.allocate(100) ;
                        EchoHandler.this.clientChannel.read(readBuffer,readBuffer,new EchoHandler(EchoHandler.this.clientChannel)) ;

                        //继续读




                    }
                }
            }

            @Override
            public void failed(Throwable exc, ByteBuffer attachment) {
                try {
                    EchoHandler.this.clientChannel.close();
                } catch (IOException e) {
                }
            }
        });
    }

    @Override
    public void failed(Throwable exc, ByteBuffer attachment) {
        try {
            this.clientChannel.close();
        } catch (IOException e) {
        }
    }
}

// 连接接收的回调处理操作
class AcceptHandler implements CompletionHandler<AsynchronousSocketChannel,AIOServerThread> {

    @Override
    public void completed(AsynchronousSocketChannel channel, AIOServerThread aioThread) {
        aioThread.getServerChannel().accept(aioThread,this) ; // 接收连接
        //正常的连接接受状态
        ByteBuffer buffer = ByteBuffer.allocate(100) ;
        channel.read(buffer,buffer,new EchoHandler(channel)) ;
        //接受客户端的请求，读出来的数据放在buffer里面
        // 读完之后，再跟一个回调函数EchoHandler
    }

    @Override
    public void failed(Throwable exc, AIOServerThread aioThread) {
        System.err.println("客户端连接创建失败....");
        aioThread.getLatch().countDown(); //减少计数
        //服务端的线程被停止掉
    }
}

// 设置一个单独的服务器的处理线程
class AIOServerThread implements Runnable {
    private AsynchronousServerSocketChannel serverChannel = null; // 服务器通道
    private CountDownLatch latch = null ; // 做一个同步处理操作
//保证代码能够一直执行下去


    public AIOServerThread() throws Exception {
        this.latch = new CountDownLatch(1) ;// 等待线程数量为1

        this.serverChannel = AsynchronousServerSocketChannel.open(); // 打开服务器的通道
        this.serverChannel.bind(new InetSocketAddress(HostInfo.PORT)) ; // 绑定端口
        System.out.println("服务器启动成功，监听端口为：" + HostInfo.PORT);
    }

    public AsynchronousServerSocketChannel getServerChannel() {
        return serverChannel;
    }

    public CountDownLatch getLatch() {
        return latch;
    }


    @Override
    public void run() {
        this.serverChannel.accept(this,new AcceptHandler()) ;

        /*public abstract <A> void accept(A attachment,
                CompletionHandler<AsynchronousSocketChannel,? super A> handler);*/

        //this 代表本Runnable线程实例
        //
        //new AcceptHandler ()连接接收的回调处理操作

        //处理完成之后，需要一个CompletionHandler 操作来处理
        try {
            this.latch.await();
            //去等待你进行一个客户端的连接，为了保证在连接之前不断开，设置一个线程等待
            // 线程等待
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}


public class AIOEchoServer {
    public static void main(String[] args) throws Exception {
        new Thread(new AIOServerThread()).start();
    }
}
